#pragma once
/*这是时间轮的源代码*/
#include <cstdint>
#include <functional>
#include <memory>
#include <unordered_map>
#include <vector>
#include <iostream>
#include <unistd.h>
#include "EventLoop.hpp"
#include <sys/timerfd.h>
class TimeTask
{
public:
    using Task = std::function<void()>;
    using ReleaseTask = std::function<void()>;

private:
    uint32_t _timeout;  // 设定的超时时间
    uint64_t _timer_id; // 设置的任务id
    Task _cb;           // 超时的回调函数
    ReleaseTask _rcb;   // 释放函数
    bool _is_cancel;    // 任务是否关闭，false是没有关闭，true是关闭

public:
    TimeTask(uint64_t time_id, uint32_t timeout, Task cb) : _timeout(timeout), _timer_id(time_id), _cb(cb), _is_cancel(false) {}
    ~TimeTask()
    {
        if (_is_cancel == false)
            _cb();
        _rcb();
    }
    uint64_t GetTimerId()
    {
        return _timer_id;
    }
    void CancelTask()
    {
        _is_cancel = true;
    }
    void SetRelease(ReleaseTask task)
    {
        _rcb = task;
    }
    uint32_t GetTimeOut()
    {
        return _timeout;
    }
};

class TimeWheel
{
    using WeakTask = std::weak_ptr<TimeTask>;
    using TaskPtr = std::shared_ptr<TimeTask>;

private:
    std::unordered_map<uint64_t, WeakTask> _timers;
    unsigned int _tick;
    unsigned int _capacity;
    std::vector<std::vector<TaskPtr>> _wheel;
    EventLoop *_loop;
    int _timerfd;
    std::unique_ptr<Channel> _timer_channel;

private:
    void ReleaseFunction(uint64_t tid)
    {
        auto it = _timers.find(tid);
        if (it != _timers.end())
        {
            _timers.erase(tid);
        }
    }
    void RemoveTimer(uint64_t id)
    {
        auto it = _timers.find(id);
        if (it != _timers.end())
        {
            _timers.erase(it);
        }
    }
    static int CreateTimerfd()
    {
        int timerfd = timerfd_create(CLOCK_MONOTONIC, 0);
        if (timerfd < 0)
        {
            ERR_LOG("TIMERFD CREATE FAILED!");
            abort();
        }
        itimerspec itime;
        itime.it_value.tv_sec = 1;
        itime.it_interval.tv_nsec = 0;
        itime.it_interval.tv_sec = 1;
        itime.it_interval.tv_nsec = 0;
        timerfd_settime(timerfd, 0, &itime, nullptr);
        return timerfd;
    }
    int ReadTimefd()
    {
        uint64_t times;
        int ret = read(_timerfd, &times, 8);
        if (ret < 0)
        {
            ERR_LOG("READ TIMEFD FAILED!");
            abort();
        }
        return times;
    }
    int RunTimerTask()
    {
        _tick = (_tick + 1) % _capacity;
        _wheel[_tick].clear();
    }
    void OnTime()
    {
        int times = ReadTimefd();
        for (int i = 0; i < times; i++)
        {
            RunTimerTask();
        }
    }
    void TimerAddInLoop(uint64_t id, uint32_t delay, const TimeTask::Task &cb)
    {
        TaskPtr pt(new TimeTask(id, delay, cb));
        pt->SetRelease(std::bind(&TimeWheel::RemoveTimer, this, id));
        int pos = (_tick + delay) % _capacity;
        _wheel[pos].push_back(pt);
        _timers[id] = WeakTask(pt);
    }
    void TimerRefreshInLoop(uint64_t id)
    {
        auto it = _timers.find(id);
        if (it == _timers.end())
        {
            return;
        }
        TaskPtr pt = it->second.lock();
        int delay = pt->GetTimeOut();
        int pos = (_tick + delay) % _capacity;
        _wheel[pos].push_back(pt);
    }
    void TimerCancelInLoop(uint64_t id)
    {
        auto it = _timers.find(id);
        if (it == _timers.end())
        {
            return; // 没找着定时任务，没法刷新，没法延迟
        }
        TaskPtr pt = it->second.lock();
        if (pt)
            pt->CancelTask();
    }

public:
    TimeWheel(EventLoop *loop) : _capacity(60), _tick(0), _wheel(_capacity), _loop(loop),
                                 _timerfd(CreateTimerfd()), _timer_channel(new Channel(_loop, _timerfd))
    {
        _timer_channel->SetReadCallback(std::bind(&TimeWheel::OnTime, this));
        _timer_channel->EnableRead(); // 启动读事件监控
    }
    /*定时器中有个_timers成员，定时器信息的操作有可能在多线程中进行，因此需要考虑线程安全问题*/
    /*如果不想加锁，那就把对定期的所有操作，都放到一个线程中进行*/
    void TimerAdd(uint64_t id, uint32_t delay, const TimeTask::Task &cb)
    {
        _loop->RunInLoop(std::bind(&TimeWheel::TimerAddInLoop, this, id, delay, cb));
    }
    // 刷新/延迟定时任务
    void TimerRefresh(uint64_t id)
    {
        _loop->RunInLoop(std::bind(&TimeWheel::TimerRefreshInLoop, this, id));
    }
    void TimerCancel(uint64_t id)
    {
        _loop->RunInLoop(std::bind(&TimeWheel::TimerCancelInLoop, this, id));
    }

    /*这个接口存在线程安全问题--这个接口实际上不能被外界使用者调用，只能在模块内，在对应的EventLoop线程内执行*/
    bool HasTimer(uint64_t id)
    {
        auto it = _timers.find(id);
        if (it == _timers.end())
        {
            return false;
        }
        return true;
    }
};
